#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
#include <assert.h>

/**
 * 多进程
 */
// int main(int argc, char const *argv[])
// {
// 	pid_t pid;
// 	int status;

// 	printf("current parent process\n");

// 	pid = fork();

// 	if(pid == -1){
// 		printf("create child process error\n");
// 		exit(0);
// 	}else if(pid == 0){
// 		int fd;
// 		setsid();

// 		fd = open("/dev/null", O_RDWR|O_CREAT, 0);
// 		dup2(fd, STDIN_FILENO);
// 		dup2(fd, STDOUT_FILENO);
// 		dup2(fd, STDERR_FILENO);

// 		//子进程
// 		printf("current child process\n");

// 		sleep(3);

// 		printf("child process exit 2\n");

// 		exit(2);
// 	}

// 	waitpid(pid, &status, 0);

// 	printf("child_process_status : %d\n", WEXITSTATUS(status));

// 	printf("parent process exit 0\n");

// 	return 0;
// }

//------------------------------多线程资源竞争锁，无条件变量---------------------------
/*
 #define MAX_PTRHEAD_SIZE 4
 #define MIN_STACK_SIZE 4194304

 static pthread_t pthread_pool[MAX_PTRHEAD_SIZE];
 static pthread_mutex_t pthread_mutex;

 static unsigned long g_total;

 static void *pthread_function_callback(void *arg){
 	int idx = (int)arg;
 	
 	while(1){
 		pthread_mutex_lock(&pthread_mutex);

 		g_total++;

 		printf("this pthread idx:%d, g_total:%d\n", idx, g_total);

 		pthread_mutex_unlock(&pthread_mutex);

 		sleep(1);
 	}
 	
 	return 0;
 }

 int main(int argc, char const *argv[])
 {
 	pthread_attr_t pthread_attr;
 	pthread_t pthread;
 	size_t stacksize;

	pthread_mutex_init(&pthread_mutex, NULL);
	g_total = 0;

 	pthread_attr_init(&pthread_attr);
 	pthread_attr_getstacksize(&pthread_attr, &stacksize);

 	while(stacksize < MIN_STACK_SIZE) stacksize *= 2;

 	pthread_attr_setstacksize(&pthread_attr, stacksize);

 	for (int i = 0; i < MAX_PTRHEAD_SIZE; ++i)
 	{
 		void *pthread_arg = (void*)i;
 		if(pthread_create(&pthread, &pthread_attr, pthread_function_callback, pthread_arg)
 			!= 0){
 			printf("create pthread error\n");
 			exit(0);
 		}else{
 			printf("create pthread success\n");
 		}

 		pthread_pool[i] = pthread;
 	}

 	while(1){
 		sleep(5);
 	}

 	return 0;
 }
*/
 

 //----------------双向列表实现的先进后出队列，多线程实现创造者与消费者模式-------------
 #define MAX_PTRHEAD_SIZE 4
 #define MIN_STACK_SIZE 4194304
 #define ASSERT(msg) assert(msg)
 //#define DEBUG

 static pthread_t pthread_pool[MAX_PTRHEAD_SIZE];
 static pthread_cond_t pthread_cond;
 static pthread_mutex_t pthread_mutex;

 typedef void (*pDestructor)(void *);

 typedef struct listNode{
 	struct listNode *pNext;
 	struct listNode *pLast;
 	void *pData;
 }listNode;

 typedef struct DoubleList{
 	struct listNode *pListHead;
 	struct listNode *pListLast;
 	listNode **nodes;
 	pDestructor destructor;
 	int length;
 }DoubleList;

 static void destructor(void *data){
 	if(data != NULL){
		free(data);
		data = NULL;
 	}
 }

 static DoubleList* List(DoubleList *list, pDestructor destructor){
 	list = (DoubleList*)malloc(sizeof(DoubleList));
 	if(list == NULL) ASSERT("malloc error");

 	list->destructor = destructor;
 	list->pListHead  = NULL;
 	list->pListLast  = NULL;
 	list->nodes		 = NULL;
 	list->length 	 = 0;

 	return list;
 }
 
 //右边加
 static int rpushDbList(DoubleList *list, void *pData){
 	listNode *p = (listNode*)malloc(sizeof(listNode));
 	p->pData = pData;

	if(list->length == 0) {
		list->nodes = p;
		list->pListHead = p;
	}else{
		list->pListLast->pNext = p;
	}
	list->pListLast = p;
	list->length++;

 #ifdef DEBUG
	printf("add address:%x\n", p);
 #endif

 	return 0;
 }

 //左边取
 static int lpopDbList(DoubleList *list, void **data){

 	if(list->length <= 0) {
 		*data = NULL;
 	}else if(list->length == 1){
 #ifdef DEBUG
 		printf("add address:%x\n", list->pListHead);
 #endif
 		*data 			= list->pListHead->pData;
 		list->nodes 	= NULL;
 		list->pListLast = NULL;
 		list->length    = 0;

 		list->destructor(list->pListHead);
 		list->pListHead = NULL;
 	}else{
 		listNode *p = list->pListHead;
 #ifdef DEBUG
 		printf("add address:%x\n", p);
 #endif
 		*data 			= p->pData;
 		list->pListHead = p->pNext;
 		list->destructor(p);
 		list->length--;
 	}

 	return 0;
 }

 static DoubleList *dblist;

 static void *pthread_function_callback(void *arg){
 	unsigned long idx = (unsigned long)arg;

 	pthread_mutex_lock(&pthread_mutex);

 	while(1){
		if(idx > 1){
	 		//createtor线程,负责向data_pool数组push数据
	 		rpushDbList(dblist, strdup("hello world"));

	 		pthread_cond_broadcast(&pthread_cond);

	 		printf("createtor thread idx:%ld\n", idx);

	 		pthread_mutex_unlock(&pthread_mutex);

	 		usleep(600000);
	 	}else{
	 		char *tmp;

	 		//expend线程，负责向data_pool数组读出并删除数据
	 		if(dblist->length == 0){
	 			pthread_cond_wait(&pthread_cond, &pthread_mutex);
	 			continue;
	 		}

	 		lpopDbList(dblist, (void**)&tmp);

	 		printf("current thread idx:%ld, expend:%s\n", idx, tmp);

	 		free(tmp);

	 		pthread_mutex_unlock(&pthread_mutex);
	 	}

	 	pthread_mutex_lock(&pthread_mutex);
 	}
 }

 int main(int argc, char const *argv[])
 {
 	pthread_attr_t attr;
 	pthread_t pthread;
 	size_t stacksize;
 	int i;

 	dblist = List(dblist, destructor);

 	pthread_mutex_init(&pthread_mutex, NULL);
 	pthread_cond_init(&pthread_cond, NULL);
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &stacksize);

 	while(stacksize < MIN_STACK_SIZE) stacksize *= 2;

 	pthread_attr_setstacksize(&attr, stacksize);

 	for (i = 0; i < MAX_PTRHEAD_SIZE; ++i)
 	{
 		void *idx = (void*)(unsigned long)i;
 		pthread_create(&pthread, &attr, pthread_function_callback, idx);

 		pthread_pool[i] = pthread;
 	}

 	while(1){
 		sleep(10);
 	}

 	return 0;
 }